using Cysharp.Threading.Tasks;
using GameFramework.Event;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace DTFramework.Entity
{
    /// <summary>
    /// 实体加载扩展
    /// </summary>
    public static class EntityExtension
    {
        private static readonly Dictionary<int, UniTaskCompletionSource<UnityGameFramework.Runtime.Entity>> s_EntityTcs =
            new Dictionary<int, UniTaskCompletionSource<UnityGameFramework.Runtime.Entity>>();

        public static int GetUniqueId(int id, int typeId) => typeId * 100000 + id;

        static EntityExtension()
        {
            EventComponent eventComponent = UnityGameFramework.Runtime.GameEntry.GetComponent<EventComponent>();
            eventComponent.Subscribe(ShowEntitySuccessEventArgs.EventId, OnShowEntitySuccess);
            eventComponent.Subscribe(ShowEntityFailureEventArgs.EventId, OnShowEntityFailure);
        }

        /// <summary>
        /// 获取目标实体
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="entityComponent">实体管理组件</param>
        /// <param name="id">实体ID</param>
        /// <param name="typeId">实体类型</param>
        /// <returns></returns>
        public static T GetGameEntity<T>(this EntityComponent entityComponent, int id, int typeId) where T : Entity
        {
            int entityId = GetUniqueId(id, typeId);
            UnityGameFramework.Runtime.Entity entity = entityComponent.GetEntity(entityId);
            if (entity == null) return null;
            return (T)entity.Logic;
        }
        /// <summary>
        /// 隐藏目标实体
        /// </summary>
        /// <param name="entityComponent">实体管理组件</param>
        /// <param name="id">实体ID</param>
        /// <param name="typeId">实体类型</param>
        public static void HideGameEntity(this EntityComponent entityComponent, int id, int typeId)
        {
            int entityId = GetUniqueId(id, typeId);
            if (entityComponent.HasEntity(entityId))
            {
                entityComponent.HideEntity(entityId);
            }
        }
        /// <summary>
        ///  异步加载实体
        /// </summary>
        public static async UniTask<TE> ShowEntityAsync<TE, TD>(this EntityComponent entityComponent, string assetName, string groupName, TD data) where TD : EntityData where TE : Entity
        {
            if (data == null)
            {
                Log.Warning("Data is invalid.");
                return null;
            }

            var logicType = typeof(TE);
            int entityId = GetUniqueId(data.Id, data.TypeId);

            if (entityComponent.HasEntity(entityId))
            {
                Log.Error("实体已经存在：" + entityId);
                return null;
            }
            var entity = await entityComponent.ShowEntityAsync(entityId, logicType, assetName, groupName, AssetPriority.EntityAsset, data);
            return entity.Logic as TE;
        }

        /// <summary>
        /// 获取实体屏幕坐标
        /// </summary>
        public static Vector2 GetWebViewScreenPos(this Entity entity,Camera camera , float defaultScreenwidth = 1920f, float defaultScreenheight = 1080f)
        {
            var widthScale = defaultScreenwidth / Screen.width;
            var heightScale = defaultScreenheight / Screen.height;
            var screenPos = camera.WorldToScreenPoint(entity.transform.position);
            var screen_x = screenPos.x * widthScale; ;
            var screen_y = screenPos.y * heightScale;

            if (Screen.width >= defaultScreenwidth)
            {
                screen_x = screenPos.x * widthScale;
                float dValue = Screen.width / defaultScreenwidth;
                int iValue = (int)dValue;
                float dScale = defaultScreenwidth * (dValue - iValue);
                screen_x += dScale / (iValue * 2);
            }
            return new Vector2(screen_x, screen_y);
        }

        /// <summary>
        /// 显示实体（可等待）
        /// </summary>
        private static UniTask<UnityGameFramework.Runtime.Entity> ShowEntityAsync(this EntityComponent entityComponent, int entityId,
            Type entityLogicType, string entityAssetName, string entityGroupName, int priority, object userData)
        {
            var tcs = new UniTaskCompletionSource<UnityGameFramework.Runtime.Entity>();
            s_EntityTcs.Add(entityId, tcs);
            entityComponent.ShowEntity(entityId, entityLogicType, entityAssetName, entityGroupName, priority, userData);
            return tcs.Task;
        }
        private static void OnShowEntitySuccess(object sender, GameEventArgs e)
        {
            ShowEntitySuccessEventArgs ne = (ShowEntitySuccessEventArgs)e;

            if (s_EntityTcs.TryGetValue(ne.Entity.Id, out var tcs))
            {
                tcs.TrySetResult(ne.Entity);
                s_EntityTcs.Remove(ne.Entity.Id);
            }
        }
        private static void OnShowEntityFailure(object sender, GameEventArgs e)
        {
            ShowEntityFailureEventArgs ne = (ShowEntityFailureEventArgs)e;

            if (s_EntityTcs.TryGetValue(ne.EntityId, out var tcs))
            {
                Log.Error(ne.ErrorMessage);
                tcs.TrySetException(new GameFramework.GameFrameworkException(ne.ErrorMessage));
                s_EntityTcs.Remove(ne.EntityId);
            }
        }
    }
}